package com.apes.framework.plugin.workflow.deployment;

import com.apes.framework.plugin.filereader.FileReader;
import com.apes.framework.plugin.workflow.WorkFlowService;
import com.apes.framework.util.ClassPathScanUtil;
import lombok.SneakyThrows;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.io.File;
import java.io.InputStream;
import java.security.MessageDigest;
import java.util.List;

/**
 * 功能：Bpmn文件解析
 *
 * @author xul
 * @create 2021-12-20 14:05
 */
@Component
public class BpmnFileReader extends FileReader implements InitializingBean {
    private static final String suffix = ".bpmn";

    private DeploymentRepository repository;
    private WorkFlowService workFlowService;

    @Value("${apes.wf.autoDeployment.enabled:false}")
    private boolean enabled;

    private List<Deployment> deployments;

    public BpmnFileReader(DeploymentRepository repository, WorkFlowService workFlowService) {
        this.repository = repository;
        this.workFlowService = workFlowService;
    }

    @Override
    public void afterPropertiesSet() {
        if (!enabled) return;
        String configFilePath = String.format("%s/form", ClassPathScanUtil.getConfigFilePath()); /** 读取外部配置文件 **/
        if (StringUtils.hasText(configFilePath)) {
            deployments = repository.findAll();
            refreshFile(configFilePath);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void parse(InputStream is, String fileAbsolutePath) {
        String md5 = calcMD5(is);
        Deployment deployment = deployments.stream().filter(m -> m.getMd5().equals(md5)).findFirst().orElse(null);
        if (deployment != null) return;
        String id = getId(fileAbsolutePath);
        deployment = deployments.stream().filter(m -> m.getId().equals(id)).findFirst().orElse(null);
        if (deployment == null) {
            deployment = new Deployment();
            deployment.setId(id);
        }
        deployment.setMd5(md5);
        repository.save(deployment);
        workFlowService.deployment(fileAbsolutePath);
    }

    private String getId(String fileAbsolutePath) {
        String[] paths = new File(fileAbsolutePath).getAbsolutePath().split("form");
        return paths[paths.length - 1].replace("\\", "/");
    }

    /**
     * 计算文件 MD5
     *
     * @param stream
     * @return 返回文件的md5字符串，如果计算过程中任务的状态变为取消或暂停，返回null， 如果有其他异常，返回空字符串
     */
    @SneakyThrows
    protected static String calcMD5(InputStream stream) {
        MessageDigest digest = MessageDigest.getInstance("MD5");
        byte[] buf = new byte[8192];
        int len;
        while ((len = stream.read(buf)) > 0) {
            digest.update(buf, 0, len);
        }
        return toHexString(digest.digest());
    }

    private static final char[] hexCode = "0123456789ABCDEF".toCharArray();

    public static String toHexString(byte[] data) {
        StringBuilder r = new StringBuilder(data.length * 2);
        for (byte b : data) {
            r.append(hexCode[(b >> 4) & 0xF]);
            r.append(hexCode[(b & 0xF)]);
        }
        return r.toString();
    }

    @Override
    public String getSuffix() {
        return suffix;
    }

    @Override
    public String[] getPackages() {
        return null;
    }

}
